<template>
  <div ref="iconSelectRef" class="icon-select">
    <el-popover :visible="popoverVisible" :width="popoverWidth" placement="bottom-end" @hide="handlePopoverHide" @show="handlePopoverShow">
      <template #reference>
        <el-input v-model="selectedIcon" class="reference" placeholder="点击选择图标" readonly @click="popoverVisible = !popoverVisible">
          <template #prepend>
            <svg-icon :icon="selectedIcon" size="1.25em"/>
          </template>
          <template #suffix>
            <el-icon :style="{ transform: popoverVisible ? 'rotate(180deg)' : 'rotate(0)', transition: 'transform .5s', }" @click="popoverVisible = !popoverVisible">
              <ArrowDown/>
            </el-icon>
          </template>
        </el-input>
      </template>

      <!-- 下拉选择弹窗 -->
      <div ref="popoverContentRef">
        <el-input ref="searchRef" v-model="searchText" clearable placeholder="搜索图标" @input="filterIcons"/>
        <el-tabs v-model="activeTab" @tab-click="handleTabClick">
          <el-tab-pane label="本地图标" name="svg">
            <el-scrollbar :height="scrollbarHeight">
              <ul class="icon-container">
                <li v-for="icon in filteredSvgIcons" :key="'svg-' + icon" class="icon-item" @click="selectIcon(icon)">
                  <el-tooltip :content="icon" :disabled="!showTooltip" effect="light" placement="bottom">
                    <svg-icon :icon="icon" size="1.25em"/>
                  </el-tooltip>
                </li>
              </ul>
            </el-scrollbar>
          </el-tab-pane>
          <el-tab-pane label="Element Plus 图标" name="element">
            <el-scrollbar :height="scrollbarHeight">
              <ul class="icon-container">
                <li v-for="icon in filteredEpIcons" :key="icon" class="icon-item" @click="selectIcon(icon)">
                  <el-tooltip :content="icon" :disabled="!showTooltip" effect="light" placement="bottom">
                    <el-icon size="1.25em">
                      <component :is="icon"/>
                    </el-icon>
                  </el-tooltip>
                </li>
              </ul>
            </el-scrollbar>
          </el-tab-pane>
        </el-tabs>
      </div>
    </el-popover>
  </div>
</template>

<script lang="ts" setup>
import { computed, nextTick, onMounted, ref, toRef } from 'vue'
import { onClickOutside } from '@vueuse/core';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import { ArrowDown } from '@element-plus/icons-vue';
import SvgIcon from './svg-icon.vue';
import bus, { KEY_RESIZE } from '@/utils/bus.ts';

defineOptions({name: 'IconSelect'})

const props = defineProps({
  modelValue: {
    type: String,
    require: false,
    default: '',
  },
  width: {
    type: Number,
    default: 475,
  },
  showTooltip: {
    type: Boolean,
    default: false
  }
});

const emit = defineEmits(['update:modelValue']);
const selectedIcon = toRef(props, 'modelValue');

const iconSelectRef = ref();
const popoverContentRef = ref();
const scrollbarHeight = ref('300px')

const activeTab = ref('svg'); // 默认激活的Tab
const searchText = ref(''); // 筛选的值
const searchRef = ref();
const popoverVisible = ref(false); // 弹窗显示状态

const svgIcons: string[] = []; // SVG图标集合
const filteredSvgIcons = ref<string[]>([]); // 过滤后的SVG图标名称集合

const epIcons: string[] = []; // Element Plus图标集合
const epIconPrefix = ref('ep:')
const filteredEpIcons = ref<string[]>([]); // 过滤后的Element Plus图标名称集合

onMounted(() => {
  loadIcons();
});

/**
 * icon 加载
 */
function loadIcons() {
  if (svgIcons.length === 0) {
    const icons = import.meta.glob('@/assets/svgs/*.svg');
    for (const path in icons) {
      const iconName = path.replace(/.*\/(.*)\.svg$/, '$1');
      svgIcons.push(iconName);
    }
  }
  filteredSvgIcons.value = svgIcons;

  if (epIcons.length === 0) {
    const epIconKeys = Object.keys(ElementPlusIconsVue)
    epIconKeys.forEach(key => {
      epIcons.push(toUnderline(key));
    })
  }
}

const toUnderline = (str: string): string => str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '')

/**
 * 选项卡切换
 */
function handleTabClick(pane: any) {
  activeTab.value = pane.paneName;
  filterIcons();
}

// 显示后触发
const handlePopoverShow = () => {
  bus.on(KEY_RESIZE, updateWidth);
  nextTick(() => {
    searchRef.value?.focus();
  });
};

// 隐藏时触发
const handlePopoverHide = () => {
  bus.off(KEY_RESIZE);
};

const clientWidth = ref(document.documentElement.clientWidth);
const updateWidth = () => {
  clientWidth.value = document.documentElement.clientWidth
}

const popoverWidth = computed(() => {
  return clientWidth.value ? Math.min(clientWidth.value - 10, props.width) : props.width;
});

/**
 * icon 筛选
 */
function filterIcons() {
  let searchTextVal = searchText.value?.toLowerCase()
  if (activeTab.value == 'svg') {
    // 过滤SVG图标逻辑
    filteredSvgIcons.value = searchTextVal
      ? svgIcons.filter((iconName) => iconName.toLowerCase().includes(searchTextVal))
      : svgIcons;
  } else {
    // 过滤Element Plus图标逻辑
    filteredEpIcons.value = searchTextVal
      ? epIcons.filter((iconName) => iconName.toLowerCase().includes(searchTextVal))
      : epIcons;
  }
}

/**
 * 选择图标
 */
function selectIcon(iconName: string) {
  if (activeTab.value == 'element') {
    iconName = epIconPrefix.value + iconName;
  }
  emit('update:modelValue', iconName);
  popoverVisible.value = false;
}

/**
 * 点击容器外的区域关闭弹窗 VueUse onClickOutside
 */
onClickOutside(iconSelectRef, () => (popoverVisible.value = false), {
  ignore: [popoverContentRef],
});

</script>

<style lang="scss" scoped>
.reference :deep(.el-input__wrapper),
.reference :deep(.el-input__inner) {
  cursor: pointer;
}

.icon-select {
  width: 100%;

  :deep(.el-input-group__prepend) {
    padding: 0 10px;
  }
}

.icon-container {
  display: flex;
  flex-wrap: wrap;
  margin-block-start: 0;
  margin-block-end: 0;
  padding-inline-start: 0;

  .icon-item {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
    margin: 4px;
    cursor: pointer;
    border: 1px solid #dcdfe6;
    border-radius: 4px;
    transition: all 0.3s;
  }

  .icon-item:hover {
    border-color: var(--el-color-primary);
    scale: 1.2;
  }
}
</style>
